//
//  ExCaptureViewController.m
//  OC-Example
//
//  Created by apang on 2020/10/15.
//  Copyright © 2020 apang.men. All rights reserved.
//

#import "ExCaptureViewController.h"

@interface VideoPreview : UIView
@property (nonatomic, strong) AVCaptureVideoPreviewLayer * videoLayer;
@end

@implementation VideoPreview

- (void)layoutSubviews {
    [super layoutSubviews];
//    if (CGRectIsEmpty(_videoLayer.frame)) {
        _videoLayer.frame = self.bounds;
//    }
}

- (void)setVideoLayer:(AVCaptureVideoPreviewLayer *)videoLayer {
    _videoLayer = videoLayer;
    [self.layer addSublayer:videoLayer];
}
@end
@interface ExCaptureViewController ()<AVCaptureVideoDataOutputSampleBufferDelegate>
@property (nonatomic, strong) dispatch_queue_t queue;
@property (nonatomic, strong) AVCaptureSession * captureSession;
@property (nonatomic, strong) AVCaptureDevice * captureDevice;
@property (nonatomic, strong) AVCaptureDeviceInput * videoInput;
@property (nonatomic, strong) AVCaptureVideoDataOutput * videoDataOutput;
@property (nonatomic, strong) VideoPreview * preview;
@property (nonatomic, assign) BOOL isPreview;
@end

@implementation ExCaptureViewController

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    switch (_orientation) {
        case OrientationUnknown:
            return UIInterfaceOrientationMaskAll;
        case OrientationPortrait:
            return UIInterfaceOrientationMaskPortrait;
        case OrientationLandscapeLeft:
            return UIInterfaceOrientationMaskLandscapeLeft;
        case OrientationPortraitUpsideDown:
            return UIInterfaceOrientationMaskPortraitUpsideDown;
        case OrientationLandscapeRight:
            return UIInterfaceOrientationMaskLandscapeRight;

        default:
            return UIInterfaceOrientationMaskAll;
    }
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    switch (_orientation) {
        case OrientationUnknown:
            return UIInterfaceOrientationUnknown;
        case OrientationPortrait:
            return UIInterfaceOrientationPortrait;
        case OrientationLandscapeLeft:
            return UIInterfaceOrientationLandscapeLeft;
        case OrientationPortraitUpsideDown:
            return UIInterfaceOrientationPortraitUpsideDown;
        case OrientationLandscapeRight:
            return UIInterfaceOrientationLandscapeRight;

        default:
            return UIInterfaceOrientationUnknown;
    }
}

- (BOOL)shouldAutorotate {
    if (_orientation == OrientationUnknown) {
        return YES;
    }
    return NO;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        self.modalPresentationStyle = UIModalPresentationOverFullScreen;
        _devicePosition = AVCaptureDevicePositionUnspecified;
        _isPreview = NO;
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self.view setBackgroundColor:[UIColor whiteColor]];
    [self preview];
    UIButton * closeBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    if (@available(iOS 13, *)) {
        UIImage * image = [UIImage systemImageNamed:@"xmark" compatibleWithTraitCollection:nil];
        [closeBtn setImage:image forState:UIControlStateNormal];
    } else {
        [closeBtn setTitle:@"关闭" forState:UIControlStateNormal];
    }
    [closeBtn addTarget:self action:@selector(onClickCloseBtn:) forControlEvents:UIControlEventTouchUpInside];
    closeBtn.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:closeBtn];
    if (@available(iOS 9.0, *)) {
        [self.view addConstraint:[closeBtn.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20]];
        if (@available(iOS 11.0, *)) {
            [self.view addConstraint:[closeBtn.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:20]];
        } else {
            [self.view addConstraint:[closeBtn.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:20]];
        }
    } else {
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(20)-[closeBtn]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(closeBtn)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(20)-[closeBtn]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(closeBtn)]];
    }
    
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    __weak typeof(self) weakSelf = self;
    [self checkCameraAuthority:^(BOOL granted, NSError * _Nullable error) {
        if (granted == YES) {
            [weakSelf configurationSession];
            [weakSelf startPreview];
        }
    }];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [self stopPreview];
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    NSLog(@"%s  %@  %@",__func__, NSStringFromCGSize(size), coordinator);
    NSLog(@"%ld",(long)self.preview.videoLayer.connection.videoOrientation);
}


- (void)onClickCloseBtn:(UIButton *)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}


- (void)configurationSession {
    _devicePosition = AVCaptureDevicePositionFront;
    [self.captureSession beginConfiguration];
    if ([self.captureSession canAddInput:self.videoInput]) {
        [self.captureSession addInput:self.videoInput];
    }
    if ([self.captureSession canAddOutput:self.videoDataOutput]) {
        [self.captureSession addOutput:self.videoDataOutput];
    }
    [self.captureSession commitConfiguration];
    [self.captureDevice lockForConfiguration:nil];
    [self.captureDevice setActiveVideoMinFrameDuration:CMTimeMake(1, 5)];
    [self.captureDevice setActiveVideoMaxFrameDuration:CMTimeMake(1, 15)];
    [self.captureDevice unlockForConfiguration];
    AVCaptureConnection * videoConnect = [self getVideoOutputConnection];
    if (videoConnect) {
        videoConnect.automaticallyAdjustsVideoMirroring = NO;
    }
    self.preview.videoLayer.connection.automaticallyAdjustsVideoMirroring = NO;
    if (_orientation != OrientationUnknown) {
        if (videoConnect) {
            [videoConnect setVideoOrientation:[self captureVideoOrientation]];
        }
        [self.preview.videoLayer.connection setVideoOrientation:[self captureVideoOrientation]];
    }
}

- (void)startPreview {
    if (_isPreview == NO) {
        [self.captureSession startRunning];
        _isPreview = YES;
    }
}

- (void)stopPreview {
    if (_isPreview) {
        [self.captureSession stopRunning];
    }
}

- (BOOL)canDeviceOpenCamera {
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if (authStatus == AVAuthorizationStatusAuthorized) {
        return YES;
    }
    return NO;
}

- (void)checkCameraAuthority:(void (^)(BOOL granted,  NSError * _Nullable error))competition {
    BOOL granted = [self canDeviceOpenCamera];
    if (granted) {
        competition(granted, nil);
    } else {
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
            competition(granted, granted ? nil : [NSError errorWithDomain:@"xxxx" code:500 userInfo:@{NSLocalizedFailureReasonErrorKey:@"没有权限"}]);
        }];
    }
}

- (dispatch_queue_t)queue {
    if (_queue == nil) {
        _queue = dispatch_queue_create("com.hualv.capture.queue", DISPATCH_QUEUE_SERIAL);
    }
    return _queue;
}

- (AVCaptureSession *)captureSession {
    if (_captureSession == nil) {
        _captureSession = [[AVCaptureSession alloc] init];
    }
    return _captureSession;
}

- (AVCaptureDevice *)captureDevice {
    if (_captureDevice == nil) {
        if (@available(iOS 10.0, *)) {
            NSMutableArray  <AVCaptureDeviceType>* deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeBuiltInWideAngleCamera,AVCaptureDeviceTypeBuiltInTelephotoCamera, AVCaptureDeviceTypeBuiltInMicrophone]];
            //10.2 AVCaptureDeviceTypeBuiltInDualCamera
            if (@available(iOS 10.2, *)) {
                [deviceTypes addObject:AVCaptureDeviceTypeBuiltInDualCamera];
            }
            //11.1 AVCaptureDeviceTypeBuiltInTrueDepthCamera
            if (@available(iOS 11.1, *)) {
                [deviceTypes addObject:AVCaptureDeviceTypeBuiltInTrueDepthCamera];
            }
            //13.0 AVCaptureDeviceTypeBuiltInUltraWideCamera AVCaptureDeviceTypeBuiltInDualWideCamera  AVCaptureDeviceTypeBuiltInTripleCamera
            if (@available(iOS 13, *)) {
                [deviceTypes addObject:AVCaptureDeviceTypeBuiltInUltraWideCamera];
                [deviceTypes addObject:AVCaptureDeviceTypeBuiltInDualWideCamera];
                [deviceTypes addObject:AVCaptureDeviceTypeBuiltInTripleCamera];
            }
            AVCaptureDeviceDiscoverySession * captureDeviceDiscovery = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeVideo position:self.devicePosition];
             _captureDevice = [captureDeviceDiscovery.devices firstObject];
            //FIXME: Multi-camera
        } else {
            // Fallback on earlier versions
            _captureDevice = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo].firstObject;
        }
    }
    return _captureDevice;
}

- (AVCaptureDeviceInput *)videoInput {
    if (_videoInput == nil) {
        _videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.captureDevice error:nil];
    }
    return _videoInput;
}

- (VideoPreview *)preview {
    if (_preview == nil) {
        _preview = [[VideoPreview alloc] init];
        [self.view addSubview:_preview];
        _preview.translatesAutoresizingMaskIntoConstraints = NO;
        if (@available(iOS 11,*)) {
            [self.view addConstraint:[_preview.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor]];
            [self.view addConstraint:[_preview.leftAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leftAnchor]];
            [self.view addConstraint:[_preview.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor]];
            [self.view addConstraint:[_preview.rightAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.rightAnchor]];
        } else {
            [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[_preview]-(0)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_preview)]];
            [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[_preview]-(0)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_preview)]];
        }
        AVCaptureVideoPreviewLayer * previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
        [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
        _preview.videoLayer = previewLayer;
    }
    return _preview;
}

- (AVCaptureVideoDataOutput *)videoDataOutput {
    if (_videoDataOutput == nil) {
        _videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
        [_videoDataOutput setAlwaysDiscardsLateVideoFrames:NO];
        //On iOS, the only supported key is kCVPixelBufferPixelFormatTypeKey. Supported pixel formats are kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, kCVPixelFormatType_420YpCbCr8BiPlanarFullRange and kCVPixelFormatType_32BGRA.
        [_videoDataOutput setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)}];
        [_videoDataOutput setSampleBufferDelegate:self queue:self.queue];
    }
    return _videoDataOutput;
}

- (AVCaptureConnection *)getVideoOutputConnection {
    for (AVCaptureConnection * connection in self.videoDataOutput.connections) {
        for (AVCaptureInputPort * port in connection.inputPorts) {
            if (port.mediaType == AVMediaTypeVideo) {
                return connection;
            }
        }
    }
    return nil;
}

- (AVCaptureVideoOrientation)captureVideoOrientation {
    AVCaptureVideoOrientation _captureVideoOrientation = AVCaptureVideoOrientationPortrait;
    switch (_orientation) {
        case OrientationPortrait:
            _captureVideoOrientation = AVCaptureVideoOrientationPortrait;
            break;
        case OrientationLandscapeLeft:
            _captureVideoOrientation = AVCaptureVideoOrientationLandscapeLeft;
            break;
        case OrientationPortraitUpsideDown:
            _captureVideoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
            break;
        case OrientationLandscapeRight:
            _captureVideoOrientation = AVCaptureVideoOrientationLandscapeRight;
            break;
        default:
            break;
    }
    return _captureVideoOrientation;
}

// 通过抽样缓存数据创建一个UIImage对象
- (UIImage *)imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer
{
    //CIImage -> CGImageRef -> UIImage
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);  //拿到缓冲区帧数据
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer];            //创建CIImage对象
    CIContext *temporaryContext = [CIContext contextWithOptions:nil];           //创建上下文
    CGImageRef cgImageRef = [temporaryContext createCGImage:ciImage fromRect:CGRectMake(0, 0, CVPixelBufferGetWidth(imageBuffer), CVPixelBufferGetHeight(imageBuffer))];
    UIImage *result = [[UIImage alloc] initWithCGImage:cgImageRef scale:1.0 orientation:UIImageOrientationLeftMirrored];  //创建UIImage对象
    CGImageRelease(cgImageRef);  //释放上下文
    return result;
}

/**识别脸部*/
-(NSArray *)detectFaceWithImage:(UIImage *)faceImag
{
    //此处是CIDetectorAccuracyHigh，若用于real-time的人脸检测，则用CIDetectorAccuracyLow，更快
    CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace
                                                  context:nil
                                                  options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];
    CIImage *ciimg = [CIImage imageWithCGImage:faceImag.CGImage];
    NSArray *features = [faceDetector featuresInImage:ciimg];

    CIFaceFeature *faceFeature = [features firstObject];
    if (faceFeature) {
        NSLog(@"bounds                  : %@",NSStringFromCGRect(faceFeature.bounds));
        NSLog(@"hasLeftEyePosition      : %d",faceFeature.hasLeftEyePosition);
        NSLog(@"leftEyePosition         : %@",NSStringFromCGPoint(faceFeature.leftEyePosition));
        NSLog(@"hasRightEyePosition     : %d",faceFeature.hasRightEyePosition);
        NSLog(@"rightEyePosition        : %@",NSStringFromCGPoint(faceFeature.rightEyePosition));
        NSLog(@"hasMouthPosition        : %d",faceFeature.hasMouthPosition);
        NSLog(@"mouthPosition           : %@",NSStringFromCGPoint(faceFeature.mouthPosition));
        NSLog(@"hasTrackingID           : %d",faceFeature.hasTrackingID);
        NSLog(@"trackingID              : %d",faceFeature.trackingID);
        NSLog(@"hasTrackingFrameCount   : %d",faceFeature.hasTrackingFrameCount);
        NSLog(@"trackingFrameCount      : %d",faceFeature.trackingFrameCount);
        NSLog(@"hasFaceAngle            : %d",faceFeature.hasFaceAngle);
        NSLog(@"faceAngle               : %frightEyeClosed",faceFeature.faceAngle);
        NSLog(@"hasSmile                : %d",faceFeature.hasSmile);
        NSLog(@"leftEyeClosed           : %d",faceFeature.leftEyeClosed);
        NSLog(@"rightEyeClosed          : %d",faceFeature.rightEyeClosed);
        NSLog(@"\n\n\n");
    }
    
    return features;
}

#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate

- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
    NSLog(@"---- %ld", (long)connection.videoOrientation);
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
